package com.nxy.cpfsfe.util.sftp;

import com.adtec.starring.exception.BaseException;
import com.jcraft.jsch.ChannelSftp;
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.Session;
import com.jcraft.jsch.SftpException;
import com.nxy.cpfsfe.enumtype.RespCd;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class SFTPTransfer {
	
	private static final Logger LOGGER = LoggerFactory.getLogger(SFTPTransfer.class);
	
	private String remoteEncode = "UTF-8";
	
	private String localEncode = "UTF-8";
	
	/**
	 * 
	 * <p>
	 * 服务名称：NCBPS组件sftp文件上传功能
	 * <p>
	 * 服务描述：使用密钥方式进行文件上传操作(返回值为一个map，其中包括retCode返回码以及retInfo返回信息两个字段，retCode=1
	 * 表示上传成功，retCode=0表示文件传输异常)
	 * 
	 * @param host
	 *            String 主机IP
	 * @param port
	 *            Integer 主机ssh2登陆端口，如果取默认值(默认值22)，传-1
	 * @param userName
	 *            String 登录用户名
	 * @param privateKey
	 *            String 私钥文件路径
	 * @param passphrase
	 *            String 私钥文件密码
	 * @param pwd
	 *            String 登录密码
	 * @param timeout
	 *            Integer 超时时间(单位：秒)
	 * @param localPath
	 *            String 本地路径
	 * @param remotePath
	 *            String SFTP端路径
	 * @return resMap Map 操作返回信息(包括返回码及返回信息)
	 * @throws Exception 抛出异常
	 */
	public Map<String, String> uploadFile(String host, Integer port, String userName,
			String privateKey, String passphrase, String pwd, Integer timeout,
			String localPath, String remotePath) throws Exception {
		
		JSch jsch = new JSch();
		Session session;
		ChannelSftp sftpChannel;

		String retMsg = null;
		Map<String, String> resMap = new HashMap<>();

		if (port == -1) {
			port = 22;
		}
		// 初始化连接参数
		session = jsch.getSession(userName, host, port);

		// 设置密钥和密码
		if (privateKey != null && !"".equals(privateKey)) {
			if (passphrase != null && !"".equals(passphrase)) {
				// 设置带口令的密钥
				jsch.addIdentity(privateKey, passphrase);
			} else {
				// 设置不带口令的密钥
				jsch.addIdentity(privateKey);
			}
		}

		// 设置登录密码
		if (pwd != null && !"".equals(pwd)) {
			session.setPassword(pwd);
		}

		session.setTimeout(timeout * 1000);
		session.setConfig("StrictHostKeyChecking", "no");
		session.connect();

		sftpChannel = (ChannelSftp) session.openChannel("sftp");
		sftpChannel.connect();

		LOGGER.debug("{} @ 使用密钥方式成功登录到SFTP服务器[{}]", new Object[] {
				"sftp文件传输组件", host });
		if (remoteEncode != null && remoteEncode.length() > 0) {
			sftpChannel.setFilenameEncoding(remoteEncode);
		}

		// 文件上传
        int result = 1;
		SFTPHandler handler = new SFTPHandler(sftpChannel, remoteEncode,localEncode);
		try {
			if (remotePath == null || remotePath.length() == 0) {
				result = 0;
				retMsg = "sftp文件传输组件" + " @ 远程路径为空";
			}
			if (localPath == null || localPath.length() == 0) {
				result = 0;
				retMsg = "sftp文件传输组件" + " @ 本地路径为空";
			}
			remotePath = handler.adjustPath(remotePath);
			localPath = handler.adjustPath(localPath);
			result = handler.upload(localPath, remotePath);
			LOGGER.debug("sftp文件传输组件 @ 操作[文件上传]的执行结果为：{}", result);
			retMsg = "sftp密钥方式上传文件成功";
		} catch (Exception e) {
			result = 0;
			retMsg = "执行操作 " + "文件上传" + " 异常。原因：" + e.getMessage();
		} finally {

		    sftpChannel.disconnect();
		    session.disconnect();

			resMap.put("retCode", String.valueOf(result));
			resMap.put("retInfo", retMsg);
		}
		return resMap;

	}
	
	/**
	 * 
	 * <p>
	 * 服务名称：NCBPS组件sftp文件下载功能
	 * <p>
	 * 服务描述：使用密钥方式进行文件下载操作(返回值为一个map，其中包括retCode返回码以及retInfo返回信息两个字段，retCode=1
	 * 表示下载成功，retCode=0表示文件传输异常)
	 * 
	 * @param host
	 *            String 主机IP
	 * @param port
	 *            Integer 主机ssh2登陆端口，如果取默认值(默认值22)，传-1
	 * @param username
	 *            String 登录用户名
	 * @param privateKey
	 *            String 私钥文件路径
	 * @param passPhrase
	 *            String 私钥文件密码
	 * @param password
	 *            登录密码
	 * @param timeout
	 *            Integer 超时时间(单位：秒)
	 * @throws Exception 抛出异常
	 */
	public void downloadFileList(
			String host, Integer port, String username,String password, Integer timeout,
			String privateKey, String passPhrase,  String localFile, String remoteFile,
			String[] fileArray, List<String> fileList) throws Exception {
		
		ChannelSftp sftpChannel = null;
		Session session = null;
		JSch jsch;

		try {
			
			jsch = new JSch();
			session = jsch.getSession(username, host, port);
			
			// 设置密钥和密码
			if (privateKey != null && !"".equals(privateKey)) {
				if (passPhrase != null && !"".equals(passPhrase))
					jsch.addIdentity(privateKey, passPhrase);
				else
					jsch.addIdentity(privateKey);
			}
			
			// 设置登录密码
			if (password != null && !"".equals(password))
				session.setPassword(password);
			
			session.setTimeout(timeout);
			session.setConfig("StrictHostKeyChecking", "no");
			session.connect();
			
			sftpChannel = (ChannelSftp) session.openChannel("sftp");
			sftpChannel.connect();
			
			LOGGER.info("成功登录到SFTP服务器[{}]", host);
			
			SFTPHandler handler = new SFTPHandler(sftpChannel, remoteEncode,localEncode);
			handler.downloadFileList(localFile, remoteFile, fileArray, fileList);
			
		} catch (SftpException se) {
			
			LOGGER.error("堆栈信息:", se);
			String errMsg = String.format("SFTP-下载文件失败,错误原因%s,错误信息:%s", se.getCause(), se.getMessage());
			LOGGER.error(errMsg);
			
			throw new BaseException(RespCd.NCPS9400, errMsg);
			
		} catch (Exception e) {
			
			LOGGER.error("下载文件失败,错误信息:{}", e.getMessage());
			throw e;
			
		} finally {
			
			if (sftpChannel != null)
				sftpChannel.disconnect();
			
			if (session != null)
				session.disconnect();
		}
	}
	
	public Map<String, String> downloadPath(
			String host, Integer port, String username,
			String privateKey, String passPhrase, String password, Integer timeout,
			String localPath, String remotePath) throws Exception {
		
		int retCode = 0;
		String retInfo = null;
		Map<String, String> retMap = new HashMap<String, String>();
		
		// 初始化连接参数
		JSch jsch = new JSch();
		Session session = jsch.getSession(username, host, port);
		
		// 设置密钥和密码
		if (privateKey != null && !"".equals(privateKey)) {
			if (passPhrase != null && !"".equals(passPhrase))
				jsch.addIdentity(privateKey, passPhrase);	// 设置带口令的密钥
			else
				jsch.addIdentity(privateKey);	// 设置不带口令的密钥
		}
		
		// 设置登录密码
		if (password != null && !"".equals(password))
			session.setPassword(password);
		
		session.setTimeout(timeout * 1000);
		session.setConfig("StrictHostKeyChecking", "no");
		session.connect();
		
		ChannelSftp sftpChannel = (ChannelSftp) session.openChannel("sftp");
		sftpChannel.connect();
		
		LOGGER.debug("成功登录到SFTP服务器[{}]", host);
		
		// 文件下载
		SFTPHandler handler = new SFTPHandler(sftpChannel, remoteEncode,localEncode);
		try {
			
			remotePath = handler.adjustPath(remotePath);
			localPath = handler.adjustPath(localPath);
			retCode = handler.downloadPath(localPath, remotePath);
			
			LOGGER.info("操作[文件下载]的执行结果为：{}", retCode);
			
			retInfo = "sftp密钥方式下载文件成功";
			
		} catch (Exception e) {
			
			retCode = 0;
			retInfo = "执行操作[文件下载]异常。原因：" + e.getMessage();
			
		} finally {
		    sftpChannel.disconnect();
		    session.disconnect();
			
			retMap.put("retCode", String.valueOf(retCode));
			retMap.put("retInfo", retInfo);
		}
		
		return retMap;
	}
	
	public void getList(
			String host, Integer port, String username, String password, Integer timeout, 
			String privateKey, String passPhrase, String remotePath, String matchPattern,
			List<String> fileList) throws Exception {
		
		ChannelSftp sftpChannel = null;
		Session session = null;
		JSch jsch;
		
		try {
			// 初始化连接参数
			jsch = new JSch();
			session = jsch.getSession(username, host, port);
			
			// 设置私钥和私钥密码
			if (privateKey != null && !"".equals(privateKey)) {
				if (passPhrase != null && !"".equals(passPhrase))
					jsch.addIdentity(privateKey, passPhrase);
				else
					jsch.addIdentity(privateKey);
			}
			
			// 设置登录密码
			if (password != null && !"".equals(password))
				session.setPassword(password);
			
			session.setTimeout(timeout);
			session.setConfig("StrictHostKeyChecking", "no");
			session.connect();
			
			sftpChannel = (ChannelSftp) session.openChannel("sftp");
			sftpChannel.connect();
			
			LOGGER.info("成功登录SFTP服务器[{}]", host);
			
			SFTPHandler handler = new SFTPHandler(sftpChannel, remoteEncode,localEncode);
			
			remotePath = handler.adjustPath(remotePath);
			
			handler.getList(remotePath, matchPattern, fileList);
			
			LOGGER.info("获取到文件列表:[{}]", fileList);
			
		} catch (SftpException se) {
			
			LOGGER.error("堆栈信息:", se);

			String errMsg = String.format("获取远程目录文件列表失败,错误原因%s,错误信息:%s", se.getCause(), se.getMessage());
			LOGGER.error(errMsg);
			
			throw new BaseException(RespCd.NCPS9400, errMsg);
			
		} catch (Exception e) {
			
			LOGGER.error("获取目录中文件列表失败,原因{}", e.getMessage());
			throw e;
			
		} finally {
			
			if (sftpChannel != null)
				sftpChannel.disconnect();
			
			if (session != null)
				session.disconnect();
		}
	}

}
